package thread;

/**
 * 多线程并发安全问题
 * 当多个线程并发操作同一临界资源，由于线程切换时机不确定，导致执行顺序出现混乱从而导致
 * 程序出现不良后果。
 * 临界资源:操作该资源的完成过程同一时刻只能被单一线程进行。
 */
public class SyncDemo {
    public static void main(String[] args) {
        Table table = new Table();
        Thread t1 = new Thread(){
            //如果run方法内部对外抛出了一个非检查异常，就意味着这个线程就结束了
            public void run(){
                while(true){
                    //如果桌子没有豆子了，getBean方法会抛出一个非检查异常
                    int bean = table.getBean();
                    Thread.yield();
                    System.out.println(getName()+":"+bean);
                }
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                while(true){
                    int bean = table.getBean();
                    Thread.yield();
                    System.out.println(getName()+":"+bean);
                }
            }
        };
        t1.start();
        t2.start();
    }
}

class Table{
    private int beans = 20;//桌子上有20个豆子
    /*
        java在语法层面上加了一个关键字synchronized.被该关键字修饰的方法称为同步方法
        即:多个线程不能同时在方法内部执行。
        将多个线程并发执行改为同步执行可有效的解决并发安全问题
        同步执行:多个线程有先后顺序的执行
     */
    public synchronized int getBean(){//从桌子上获取一颗豆子并返回该豆子的编号
        if(beans==0){//首先判断桌子上是否还有剩余的豆子
            throw new RuntimeException("桌子上没有豆子了!");
        }
        //该方法是让执行这个方法的线程主动放弃本次剩余时间片
        Thread.yield();//这里放弃时间片目的是模拟执行完上面的if后时间片用尽发生线程切换
        return beans--;//从桌子上取出一个豆子并返回
    }
}






